<?php

declare(strict_types=1);

namespace think\generation\command;

use think\console\Command;
use think\facade\Db;
use think\helper\Str;
use think\console\Input;
use think\console\Output;
use think\generation\constant\MySqlConstant;
use think\generation\utils\StringUtil;

class BatchMakeModel extends Command
{

    protected function configure()
    {
        // 指令配置
        $this->setName('batch:make:model')
            // ->addArgument("modelName", Argument::REQUIRED, 'model名称 或 all')
            ->setDescription('批量创建Model');
    }

    protected function getStub()
    {
        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
    }

    protected function getNamespace(): string
    {
        return 'app\\model';
    }

    protected function execute(Input $input, Output $output)
    {
        $tables = Db::getTables();

        foreach ($tables as $tableName) {
            $this->makeFile($tableName);
        }
    }

    protected function makeFile($tableName)
    {
        $output = $this->output;
        $classname = $this->getClassName($tableName);
        $pathname = $this->getPathName($classname);

        if (is_file($pathname)) {
            $output->writeln('<error>' . $classname . ' already exists!</error>');
            return ;
        }

        if (!is_dir(dirname($pathname))) {
            mkdir(dirname($pathname), 0755, true);
        }

        file_put_contents($pathname, $this->buildClass($tableName, $classname));

        $output->writeln('<info>' . $classname . ' created successfully.</info>');
    }

    protected function buildClass(string $tableName, string $className)
    {
        $stub = file_get_contents($this->getStub());

        $namespace = $this->getNamespace();


        return str_replace(
            [
                '{%className%}',
                '{%actionSuffix%}',
                '{%namespace%}',
                '{%app_namespace%}',
                '{%tableName%}',
                '{%fieldAnnotation%}',
                '{%UseSoftDelete%}',
                '{%SoftDeleteFunction%}',
                '{%tableComment%}',
            ],
            [
                $className,
                $this->app->config->get('route.action_suffix'),
                $namespace,
                $this->app->getNamespace(),
                $tableName,
                $this->buildFieldsAnnotation($tableName),
                $this->buildUseSoftDelete($tableName),
                $this->buildSoftDeletefunction($tableName),
                Db::table('INFORMATION_SCHEMA.TABLES')
                    ->where("TABLE_SCHEMA", env('DATABASE.DATABASE'))
                    ->where('TABLE_NAME', $tableName)
                    ->value("TABLE_COMMENT")
            ],
            $stub
        );
    }

    private function isExistsDeleteField($tableName): bool
    {
        $fields = Db::getFields($tableName);
        $isExistsDelete = false;
        foreach ($fields as $field) {
            if (strstr($field['name'], 'delete_time')) {
                $isExistsDelete = true;
            }
        }
        if ($isExistsDelete) {
            return true;
        }
        return false;
    }

    private function buildSoftDeletefunction($tableName)
    {
        if ($this->isExistsDeleteField($tableName)) {
            return 'use SoftDelete;' . PHP_EOL .
                'protected $deleteTime = \'delete_time\';' . PHP_EOL .
                'protected $defaultSoftDelete = 0;' . PHP_EOL;
        }
        return '';
    }

    private function buildUseSoftDelete($tableName)
    {
        if ($this->isExistsDeleteField($tableName)) {
            return 'use think\model\concern\SoftDelete;';
        }
        return '';
    }

    private function buildFieldsAnnotation($tableName)
    {


        $content = '';

        $fields = Db::getFields($tableName);

        foreach ($fields as $fieldName => $value) {
            $content .= PHP_EOL . "* @property  " .
                (MySqlConstant::FIELD_MAPPING[StringUtil::getFieldType($value['type'])] ?? "未知类型" . StringUtil::getFieldType($value['type'])) .
                " $" . $value['name'] . " {$value['comment']} ";
        }

        return $content;
    }

    protected function getPathName(string $name): string
    {

        return $this->app->getBasePath() . '/model/' . $name . '.php';
    }

    protected function getClassName(string $name): string
    {
        $prefix = env("DATABASE.prefix");
        if ($prefix && strpos($name, $prefix) === 0) {
            $name = substr($name, strlen($prefix));
        }
        return Str::studly($name) . 'Model';
    }
}
